// 采用类的方式进行封装会让方法更具有复用性，也可以方便进行添加新的属性和方法
class WxRequest {
  // 定义实例属性，作为默认的参数
  default = {
    baseURL: '', // 请求基准地址
    url: '', // 开发者服务器接口地址
    data: null, // 请求参数
    method: 'GET', // 默认请求方法
    // 请求头
    header: {
      'Content-type': 'application/json' // 设置数据的交互格式
    },
    timeout: 60000, // 小程序默认超时时间是一分钟
    isLoading: true //是否显示默认的加载效果
  }

  // 定义默认拦截器
  interceptors = {
    request: (config) => {
      return config
    },
    response: (response) => {
      return response
    }
  }
  // 定义数组队列，用于完善loading
  queue = []

  // 定义 constructor 构造函数，用于创建和初始化类的属性和方法
  // 在实例化时，传入的参数会被constructor接收
  constructor(params = {}) {
    // 与默认参数合并
    this.default = Object.assign({}, this.default, params)
  }

  request(options) {
    // url拼接
    options.url = this.default.baseURL + options.url
    // 合并完整请求参数
    options = { ...this.default, ...options }
    // 在拦截器之前使用加载效果，上传文件API有加载效果
    if (options.isLoading && options.method !== 'UPLOAD') {
      // 解决同时请求多个接口时，loading应等所有请求完成再关闭
      this.queue.length === 0 && wx.showLoading()
      // 自定义push内容
      // 队列中添加 request 标识，代表需要发送一次新请求
      this.queue.push('request')
    }
    // 在发送请求之前调用请求拦截器
    options = this.interceptors.request(options)
    return new Promise((resolve, reject) => {
      // upload或者request请求
      if (options.method === 'UPLOAD') {
        wx.uploadFile({
          ...options,
          success: (res) => {
            // res.data会返回字符串，需要转化为对象
            res.data = JSON.parse(res.data)
            const mergeRes = Object.assign({}, res, { config: options, isSuccess: true })
            resolve(this.interceptors.response(mergeRes))
          },
          fail: (error) => {
            const mergeError = Object.assign({}, error, { config: options, isSuccess: false })
            reject(this.interceptors.response(mergeError))
          }
        })
      } else {
        wx.request({
          ...options,
          success: (res) => {
            // 添加isSuccess状态表示服务器是否成功响应
            const mergeRes = Object.assign({}, res, { config: options, isSuccess: true })
            resolve(this.interceptors.response(mergeRes))
          },
          fail: (error) => {
            const mergeError = Object.assign({}, error, { config: options, isSuccess: false })
            reject(this.interceptors.response(mergeError))
          },
          complete: () => {
            if (options.isLoading) {
              // 队列中删除 request 标识
              this.queue.pop()
              // 如果队列中没有 request 标识，代表所有请求都已完成，关闭loading
              if (this.queue.length === 0) {
                wx.hideLoading()
              }
            }
          }
        })
      }
    })
  }

  // 封装请求快捷方法
  get(url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'GET' }, config))
  }
  post(url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'POST' }, config))
  }
  put(url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'PUT' }, config))
  }
  delete(url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'DELETE' }, config))
  }

  // 封装并发请求
  // 使用展开运算符将传入的参数转成数组
  all(...requests) {
    return Promise.all(requests)
  }

  // 封装upLoadFile
  upload(url, filePath, name, config = {}) {
    return this.request(Object.assign({ url, filePath, name, method: 'UPLOAD' }, config))
  }
}
export default WxRequest
